<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>关于 draw.io 矢量图 SVG 导出的研究 | blog</title>
<meta name="generator" content="Jekyll v3.9.2" />
<meta property="og:title" content="关于 draw.io 矢量图 SVG 导出的研究" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="draw.io 是一个很简单易用的矢量图绘制工具, 画一些简单的图标或者流程图等等都很适合. 虽然好用, 但是在导出 *.drawio 文件为其他格式 (位图 PNG, 矢量图 SVG) 时, 大多数时候都需要额外注意." />
<meta property="og:description" content="draw.io 是一个很简单易用的矢量图绘制工具, 画一些简单的图标或者流程图等等都很适合. 虽然好用, 但是在导出 *.drawio 文件为其他格式 (位图 PNG, 矢量图 SVG) 时, 大多数时候都需要额外注意." />
<link rel="canonical" href="https://tsagaanbar.gitee.io/blog/tech/drawio-svg-exports/" />
<meta property="og:url" content="https://tsagaanbar.gitee.io/blog/tech/drawio-svg-exports/" />
<meta property="og:site_name" content="blog" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2022-05-17T20:06:11+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="关于 draw.io 矢量图 SVG 导出的研究" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2022-05-17T20:06:11+00:00","datePublished":"2022-05-17T20:06:11+00:00","description":"draw.io 是一个很简单易用的矢量图绘制工具, 画一些简单的图标或者流程图等等都很适合. 虽然好用, 但是在导出 *.drawio 文件为其他格式 (位图 PNG, 矢量图 SVG) 时, 大多数时候都需要额外注意.","headline":"关于 draw.io 矢量图 SVG 导出的研究","mainEntityOfPage":{"@type":"WebPage","@id":"https://tsagaanbar.gitee.io/blog/tech/drawio-svg-exports/"},"url":"https://tsagaanbar.gitee.io/blog/tech/drawio-svg-exports/"}</script>
<!-- End Jekyll SEO tag -->

    <link rel="stylesheet" href="/blog/assets/css/style.css?v=5a3a055c96aa4035d7a987d1ed733ff6fc09a8b3">
    <!-- start custom head snippets, customize with your own _includes/head-custom.html file -->

<!-- Setup Google Analytics -->



<!-- You can set your favicon here -->
<!-- link rel="shortcut icon" type="image/x-icon" href="/blog/favicon.ico" -->

<!-- end custom head snippets -->

  </head>
  <body>
    <div class="container-lg px-3 my-5 markdown-body">
      
      <p><a href="https://tsagaanbar.gitee.io/blog/">tsagaanbar's Blog</a></p>
      

      <p><a href="https://github.com/jgraph/drawio">draw.io</a> 是一个简单易用的图表 (diagram) 绘制工具 <sup id="fnref:app-page" role="doc-noteref"><a href="#fn:app-page" class="footnote" rel="footnote">1</a></sup>, 可以用作一个简单的矢量图绘制工具, 画一些简单的图标或者流程图等等都很适合.</p>

<p>虽然好用, 但是在导出 <code class="language-plaintext highlighter-rouge">*.drawio</code> 文件为其他格式时, 大多数时候都需要额外注意.</p>

<h2 id="导出设计时会遇到的问题及原因">导出设计时会遇到的问题及原因</h2>

<p>对于 PNG 导出, 默认的设置下, 导出的图像会很模糊.  幸运的是, 可以在导出时通过将图表的缩放比例调制 250% ~ 300% (甚至更高) 来解决. <sup id="fnref:png-export" role="doc-noteref"><a href="#fn:png-export" class="footnote" rel="footnote">2</a></sup></p>

<p>至于 SVG, 事情就变得有点复杂. 在浏览器中查看软件导出的 SVG 文件时, 一切似乎都很好. 但是, 当尝试将这些 SVG 导入 Word 或 Inkscape 等软件时，则可能会看到图片上出现 “<strong>Viewer does not support full SVG 1.1</strong> (查看器不支持完整的 SVG 1.1)” 字样 <sup id="fnref:info-updated" role="doc-noteref"><a href="#fn:info-updated" class="footnote" rel="footnote">3</a></sup>.</p>

<figure>
<p>图片暂时省略</p>
<figcaption>图 1: 在 draw.io 中绘制的图片</figcaption>
</figure>

<figure>
<p>图片暂时省略</p>
<figcaption>图 2: 显示异常的图片</figcaption>
</figure>

<p>大多数情况下, 这种情况是因为 draw.io 使用了 HTML 代码来标记文本框中的自动换行的长文本 / 复杂格式的文本 / (或者还有其他的图元), 并将这些代码直接嵌入到了 SVG 的 <code class="language-plaintext highlighter-rouge">&lt;foreignObject&gt;</code> 标签中.</p>

<p>现代浏览器自然是能够解析这些 HTML 代码的, 因此在其中查看不会出现太多的问题. 然而这些 “外来 (foreign)” 的 HTML 代码并不能被 Inkscape 等专门处理 SVG 的软件理解.</p>

<p>因此, draw.io 的开发人员在 SVG 中加入了一个 <code class="language-plaintext highlighter-rouge">&lt;switch&gt;</code> 标签, 使得不支持 <code class="language-plaintext highlighter-rouge">&lt;foreignObject&gt;</code> 中内容的查看器在渲染这样的 SVG 时, 会显示上述的提示信息文本.</p>

<p>总之, 并不是这些查看器 “不支持 SVG 1.1”, 而是因为这些 SVG 中 <code class="language-plaintext highlighter-rouge">&lt;foreignObject&gt;</code> 部分包含了不能被浏览器 (或者其他能渲染 HTML 的程序) 之外的程序所解析的内容.</p>

<blockquote>
  <p>另一方面, 尽管浏览器能够查看这些 SVG, 但是对于浏览器来说, 事实上 SVG 代码才是 “外来 (foreign)’ 之物. <sup id="fnref:svg-foreign-to-web-browser" role="doc-noteref"><a href="#fn:svg-foreign-to-web-browser" class="footnote" rel="footnote">4</a></sup></p>
</blockquote>

<p>至于目前 draw.io 对于这长文本 / 复杂格式文本的 SVG 后备方案, draw.io 只是输出了一段修剪过后的文本, 十分没用.</p>

<p>不过, 按照 draw.io 的一位开发人员的说法, 其实 draw.io 这个项目最开始并不是为了画图, 更没有导出 SVG 的选项; 就连现在, 其定位也不是一个矢量图绘制软件. 所以, 对于开发者来说, 上述这些, 并不能算是软件的 BUG, 甚至不用去理会.</p>

<h2 id="解决方案">解决方案</h2>

<h3 id="法-1-禁用换行与文本格式">法 1: 禁用换行与文本格式</h3>

<p>目前, 官方博客中给出的解决方法, 就是手动全选图表上的元素, 在 “格式面板 (Format Pannel)” 的 “<strong>Text</strong> (文本)” 选项卡下, <strong>手动禁用</strong>掉 “<strong>Word Wrap</strong> (自动换行)” 和 “<strong>Formatted Text</strong> (格式化文本)”. <sup id="fnref:disable-text-options" role="doc-noteref"><a href="#fn:disable-text-options" class="footnote" rel="footnote">5</a></sup></p>

<p>这样处理之后, draw.io 导出的 SVG 就会干干净净的了 (不含 <code class="language-plaintext highlighter-rouge">&lt;foreignObject&gt;</code>, 可以被 Word 等软件正常读取).</p>

<p>需要注意的是:</p>

<ul>
  <li>禁用 “自动换行” 后, 之前适应文本框大小自动换行的文本将变为一行, 需要手动键入换行符将长文本分成多行;</li>
  <li>禁用 “格式化文本” 后, 一个文本框中将不支持多种格式的文本, 必须以一个文本框为单位整体调整文本的样式.</li>
</ul>

<p>每次手动禁用这些选项可能会有点麻烦, 可以直接 “禁用 <code class="language-plaintext highlighter-rouge">&lt;foreignObject&gt;</code> 的使用”:</p>

<ul>
  <li>如果是在线使用 <a href="https://app.diagrams.net">app.diagrams.net</a>, 可以直接访问 <a href="https://app.diagrams.net/#_CONFIG_UzV3UjUyyk0tSk8F0qrGjqpggeLM3IKcVJ/EpNScYoh4SVFpqqq5CxABAA==">app.diagrams.net/#_CONFIG_UzV3UjUyyk0tSk8F0qrGjqpggeLM3IKcVJ/EpNScYoh4SVFpqqq5CxABAA==</a>, 直接配置对应的设置 <sup id="fnref:click-to-config" role="doc-noteref"><a href="#fn:click-to-config" class="footnote" rel="footnote">6</a></sup>;</li>
  <li>或者在软件的 “其他” 选项中选择 “配置 (Configuration)”, 添加键值对 <code class="language-plaintext highlighter-rouge">"simpleLabels": true</code>, 结果如下:
    <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="w">
   </span><span class="nl">"simpleLabels"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
   </span><span class="err">//</span><span class="w"> </span><span class="err">Other</span><span class="w"> </span><span class="err">configurations...</span><span class="w">
 </span><span class="p">}</span><span class="w">
</span></code></pre></div>    </div>
  </li>
</ul>

<h3 id="法-2-导出-pdf-后再转换为-svg">法 2: 导出 PDF 后再转换为 SVG</h3>

<p>我们知道, PDF 中的数据一般是没有上下文语义的; 可以说, 它只包含各个元素的样式以及对应的位置, 是一种用来存储排版结果的格式, 并不会轻易改变. <sup id="fnref:pdf" role="doc-noteref"><a href="#fn:pdf" class="footnote" rel="footnote">7</a></sup></p>

<p>由于浏览器能够渲染排版这样包含 HTML 的 SVG, 并且浏览器一般具有 (将排版后的页面内容) 导出为 (打印为) PDF 的功能 <sup id="fnref:print-to-pdf" role="doc-noteref"><a href="#fn:print-to-pdf" class="footnote" rel="footnote">8</a></sup>. 于是, 可以利用该功能, 将浏览器对该 SVG 的排版结果导出到 PDF 里, 再通过 Inkscape 从 PDF 中还原 SVG.</p>

<p>PDF 中包含的一般是稳定的格式, 从中还原出的 SVG 自然也相对稳定 (可能由于字体因素产生些许失真).</p>

<p>不过, 经过生成 PDF 再复原的过程, 一般会丧失许多 SVG 的语义, 比如文本不再能够被连贯的复制出来; 如果生成 PDF 的过程进行了转曲的操作, 这些文本可能甚至不再能够被选取复制.</p>

<blockquote>
  <p>最新 draw.io 的 SVG 导出选项中可以修改 “文本设置”, 有一个 “将文本标签 (label) 转换为 SVG” 的选项. 据开发者所说, 就是将该文件上传到他们的服务器, 以进行上述的转换.</p>
</blockquote>

<h3 id="小结">小结</h3>

<p>综上, 目前有这些可行的解决方案：</p>

<ul>
  <li>对于简单的 SVG 图表 (不包含长文本 / 复杂格式文本), 只需按照上面提到的方法操作即可;</li>
  <li>尝试 (使用浏览器) 将 SVG 导出为 PDF, 然后使用 Inkscape 从 PDF 生成 SVG.</li>
</ul>

<h2 id="其他资料">其他资料</h2>

<p>关于这个事情, 有一些相关的有意思的讨论可以围观:</p>

<ul>
  <li><a href="https://github.com/jgraph/drawio/issues/774">Issue #774 · jgraph/drawio</a>;</li>
  <li><a href="https://inkscape.org/forums/other/inkscape-viewer-does-not-support-full-svg-11/">Inkscape “Viewer does not support full SVG 1.1” - Using Inkscape with Other Programs - Inkscape Forum</a> (还提到了 <a href="https://en.wikipedia.org/wiki/XSLT" title="XSLT - Wikipedia">XSLT</a>)</li>
  <li><a href="https://news.ycombinator.com/item?id=29753638">Truly Headless Draw.io Exports - Hacker News (ycombinator.com)</a> (提到了关于 “导出”, “SVG 暗黑模式适配” 等问题)</li>
</ul>

<hr />

<p>其他可能有用的文章:</p>

<ul>
  <li>
    <p><a href="https://www.freecodecamp.org/news/things-you-need-to-know-about-working-with-svg-in-vs-code-63be593444dd/">Things you need to know about working with SVG in VS Code (freecodecamp.org)</a></p>
  </li>
  <li>
    <p><a href="https://tomd.xyz/how-i-use-drawio/">How I use draw.io at the command line | Tom Donohue</a> 以及下边的评论:</p>

    <ul>
      <li>用代码画图 / 代码形式的图表: <a href="https://www.structurizr.com/">Structurizr</a>;</li>
      <li>一个基于 Web 的 PlantUML 编辑器: <a href="http://www.plantuml.com/plantuml">http://www.plantuml.com/plantuml</a>;</li>
      <li>…</li>
    </ul>
  </li>
  <li>
    <p>处理已压缩的 <code class="language-plaintext highlighter-rouge">.drawio</code> 文件 (可以在 ‘properties’ 中删除): <a href="https://stackoverflow.com/questions/46699903/text-editing-a-draw-io-file-exported-as-svg-with-embedded-drawing">Text-editing a draw.io file exported as SVG with embedded drawing - Stack Overflow</a></p>
  </li>
  <li>
    <p><a href="https://www.oreilly.com/library/view/svg-text-layout/9781491933817/ch04.html">4. Multiline SVG Text - SVG Text Layout [Book] (oreilly.com)</a>;</p>
  </li>
  <li>
    <p><a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element#svg_elements_by_category">SVG element reference | MDN</a> 以及 <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/text"><code class="language-plaintext highlighter-rouge">&lt;text&gt;</code> 元素的文档</a>;</p>
  </li>
</ul>

<hr />

<ul>
  <li><a href="https://blog.csdn.net/Casperflip/article/details/110129607">解决draw.io生成SVG矢量图导入Word显示有误的问题以及推荐几种SVG绘图方法 - CSDN</a></li>
  <li><a href="https://zodiaclab.top/随笔/draw-io-导出-SVG-图片报错/">draw.io 导出 SVG 图片报错</a></li>
</ul>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:app-page" role="doc-endnote">
      <p>可以访问 <a href="https://app.diagrams.net">app.diagrams.net</a> 在线使用, 也有很多平台提供 draw.io 的换皮版本. <a href="#fnref:app-page" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:png-export" role="doc-endnote">
      <p>参见 <a href="https://desk.draw.io/support/solutions/articles/16000059691-export-a-diagram-as-a-higher-resolution-png-image">Export a diagram as a higher resolution PNG image : draw.io is becoming diagrams.net</a>. <a href="#fnref:png-export" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:info-updated" role="doc-endnote">
      <p>最新版中, 文本已更改为 “Text is not SVG - cannot display”, 即 “文本不是 SVG - 无法显示”. <a href="#fnref:info-updated" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:svg-foreign-to-web-browser" role="doc-endnote">
      <p>引用自 <a href="https://inkscape.org/forums/other/inkscape-viewer-does-not-support-full-svg-11/">Inkscape 论坛</a> 中 <a href="https://inkscape.org/forums/other/inkscape-viewer-does-not-support-full-svg-11/#c32375">@Xav 的回答</a>. <a href="#fnref:svg-foreign-to-web-browser" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:disable-text-options" role="doc-endnote">
      <p>参见 <a href="https://www.diagrams.net/doc/faq/svg-export-text-problems">Why text in exported SVG images may not display correctly (diagrams.net)</a> <a href="#fnref:disable-text-options" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:click-to-config" role="doc-endnote">
      <p>来自 <a href="https://inkscape.org/forums/other/inkscape-viewer-does-not-support-full-svg-11/">Inkscape 论坛</a> 下的 <a href="https://inkscape.org/forums/other/inkscape-viewer-does-not-support-full-svg-11/#c32511">回复</a> <a href="#fnref:click-to-config" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:pdf" role="doc-endnote">
      <p>可以参考视频 “<a href="https://www.bilibili.com/video/BV1Mr4y1679f">PDF 里, 到底都是些什么 - 哔哩哔哩</a>”. <a href="#fnref:pdf" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:print-to-pdf" role="doc-endnote">
      <p>通常, 这个选项可以在上下文菜单的 “分享”, “打印” / “另存为 PDF” 中找到. <a href="#fnref:print-to-pdf" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>


      
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/anchor-js/4.1.0/anchor.min.js" integrity="sha256-lZaRhKri35AyJSypXXs4o6OPFTbTmUoltBbDCbdzegg=" crossorigin="anonymous"></script>
    <script>anchors.add();</script>
  </body>
</html>
